export default class DataBuffer {
  private readonly buffer: Buffer;
  private readonly bufferSize: number;
  private currentSize = 0;

  constructor(size: number, unsafe = false) {
    this.buffer = unsafe ? Buffer.allocUnsafe(size) : Buffer.alloc(size);
    this.bufferSize = size;
  }

  /**
   * 有效数据长度
   */
  get size() {
    return this.currentSize;
  }

  append(buf: Buffer) {
    const len = buf.byteLength;
    const nextSize = this.currentSize + len;
    if (nextSize >= this.bufferSize) {
      buf.copy(this.buffer, this.currentSize, 0, nextSize - this.bufferSize);
      this.currentSize = this.bufferSize;
    } else {
      buf.copy(this.buffer, this.currentSize, 0, len);
      this.currentSize = this.currentSize + len;
    }
  }

  hasData() {
    return this.currentSize > 0;
  }

  clear() {
    this.buffer.fill(0, 0, this.bufferSize);
    this.currentSize = 0;
  }

  first() {
    return this.buffer[0];
  }

  get(index: number) {
    return this.buffer[index];
  }

  /**
   * 平移缓冲数据
   * @param index 开始索引,从此开始之前的将被移除,后面的数据往前移
   */
  unshift(index: number) {
    if (index > 0 && index <= this.bufferSize) {
      const remainBuf = this.slice(index, this.currentSize);
      remainBuf.copy(this.buffer, 0, 0, remainBuf.length);
      this.currentSize = remainBuf.length;
      this.buffer.fill(0, this.currentSize);
    }
  }

  /**
   * 缓冲数据切片，不会改变原数据
   * @param start
   * @param end
   */
  slice(start: number, end?: number) {
    end ??= this.currentSize;
    const buffer = Buffer.allocUnsafe(end - start);
    this.buffer.copy(buffer, 0, start, end);
    return buffer;
  }

  /**
   * 从缓冲数据中剪下一段数据，原数据将被改变
   * @param start
   * @param end
   */
  cut(start: number, end: number) {
    const buf = this.slice(start, end);
    const remainBuf = this.slice(end, this.currentSize);
    // 后面往前移
    remainBuf.copy(this.buffer, start, 0);
    // 移动后剩余的填0
    this.currentSize -= buf.length;
    this.buffer.fill(0, this.currentSize);
    return buf;
  }

  /**
   * 查找指定值的索引
   * @param start 起始索引
   * @param val 指定值
   */
  findIndex(start: number, val: number | number[]) {
    if (Array.isArray(val)) {
      const pLen = val.length;
      outer: for (let i = start; i < this.bufferSize; i++) {
        const subData = this.buffer.subarray(i, i + pLen);
        // 比较两个数组是否完全相等
        for (let j = 0; j < pLen; j++) {
          if (val[j] !== subData[j]) {
            continue outer;
          }
        }
        return i;
      }
    } else {
      for (let i = start; i < this.bufferSize; i++) {
        if (val === this.buffer[i]) {
          return i;
        }
      }
    }
    return -1;
  }
}
